package com.cyy;

/**
 * 循环对列
 * @author 会玩的洋洋
 * @since 2022-02-22
 * @param <E>
 *
 * 循环队列底层用数组实现
 */
public class CircleQueue<E> {
    /**
     * 队头下标
     */
    private int frontIndex = 0;
    /**
     * 元素个数
     */
    private int size;
    /**
     * 存储元素 （队列）
     */
    private E[] elements;
    /**
     * 默认容量大小 10
     */
    private final static int DEFAULT_CAPACITY = 10;

    public CircleQueue() {
        this(DEFAULT_CAPACITY);
    }

    public CircleQueue(int capacity) {
        capacity = Math.max(capacity, DEFAULT_CAPACITY);
        elements = (E[]) new Object[capacity];
        size = 0;
    }

    /**
     * 元素个数
     * @return int
     */
    public int size() {
        return size;
    }

    /**
     * 判断队列是否为空
     * @return boolean
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 入队操作
     * @param element 入队元素
     */
    public void enQueue(E element) {
        ensureCapacity(size + 1);
        elements[index(size)] = element;
        size++;
    }

    /**
     * 出队操作
     * @return E
     */
    public E deQueue() {
        E oldElement = elements[frontIndex];
        elements[frontIndex] = null;
        // 计算队头下标  直接 frontIndex + 1
        frontIndex = index(1);
        size--;
        return oldElement;
    }

    /**
     * 获取队头元素
     * @return E
     */
    public E front() {
        return elements[frontIndex];
    }

    /**
     * 计算下标
     * @param index 传入的下标
     * @return int
     */
    private int index(int index) {
        return (frontIndex + index) % elements.length;
    }

    /**
     * 清空元素
     */
    public void clear() {
        for (int i = 0; i < size; i++) {
            elements[index(i)] = null;
        }
        frontIndex = 0;
        size = 0;
    }

    /**
     * 扩容操作
     * @param capacity 当前传入容器大小
     */
    private void ensureCapacity(int capacity) {
        int oldCapacity = elements.length;
        if (capacity <= oldCapacity) {
            return;
        }

        // 扩容 深度 copy 扩容为原来的 1.5 倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        E[] newElements = (E[])new Object[newCapacity];
        for (int i = 0; i < oldCapacity; i++) {
            newElements[i] = elements[index(i)];
        }

        elements = newElements;
        frontIndex = 0;
    }

    @Override
    public String toString() {
        StringBuilder string = new StringBuilder();
        string.append("capcacity=").append(elements.length)
                .append(" size=").append(size)
                .append(" front=").append(frontIndex)
                .append(", [");
        for (int i = 0; i < elements.length; i++) {
            if (i != 0) {
                string.append(", ");
            }

            string.append(elements[i]);
        }
        string.append("]");
        return string.toString();
    }
}
